package com.todo.event.activity.application.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.api.client.util.Lists;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.common.utils.DateUtils;
import com.todo.component.redis.RedisService;
import com.todo.event.activity.application.convert.EventActivityConvert;
import com.todo.event.activity.application.core.ab.ABHelper;
import com.todo.event.activity.application.core.ab.SampleFlowConfig;
import com.todo.event.activity.application.core.frequency.FrequencyConf;
import com.todo.event.activity.application.core.frequency.FrequencyHelper;
import com.todo.event.activity.application.entity.bo.EventActivityBO;
import com.todo.event.activity.application.entity.bo.EventActivityExecuteInfoBO;
import com.todo.event.activity.application.entity.bo.EventActivityRuleBO;
import com.todo.event.activity.application.entity.condition.EventActivityConditionBO;
import com.todo.event.activity.application.service.EventActivityService;
import com.todo.event.activity.common.base.EventKeyBuild;
import com.todo.event.activity.common.enums.EventActivityStatusEnum;
import com.todo.common.utils.TodoCommonUtils;
import com.todo.event.activity.infrastructure.entity.condition.EventActivityCondition;
import com.todo.event.activity.infrastructure.entity.po.EventActivityPO;
import com.todo.event.activity.infrastructure.repository.EventActivityRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author azhebuxing
 * @date 2025/1/7 13:14
 * @description
 */
@Slf4j
@Service
public class EventActivityServiceImpl implements EventActivityService {

    @Resource
    private EventActivityRepository eventActivityRepository;
    @Resource
    private RedisService redisService;
    @Resource
    private FrequencyHelper frequencyHelper;
    @Resource
    private ABHelper abHelper;


    @Override
    public Boolean insertEventActivity(EventActivityBO eventActivityBO) {
        if (eventActivityBO == null) {
            return false;
        }
        if (eventActivityBO.getStartTime() == null || eventActivityBO.getEndTime() == null || eventActivityBO.getStartTime().after(eventActivityBO.getEndTime())) {
            log.error("EventActivityService#insertEventActivity 新增活动数据操作失败，活动时间数据为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "活动时间数据异常");
        }
        if (eventActivityBO.getDecisionId() == null || eventActivityBO.getExecuteRule() == null || CollectionUtils.isEmpty(eventActivityBO.getExecuteInfoBOList())) {
            log.error("EventActivityService#insertEventActivity 新增活动数据操作失败，核心数据为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "核心为空");
        }
        //基础规则验证
        EventActivityRuleBO executeRule = eventActivityBO.getExecuteRule();
        if (executeRule.getHitBlackList() && executeRule.getBlackClassify() == null) {
            log.error("EventActivityService#insertEventActivity 新增活动数据操作失败，黑名单规则为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "黑名单规则为空");
        }
        if (executeRule.getHitCrowd() && executeRule.getCrowdClassify() == null) {
            log.error("EventActivityService#insertEventActivity 新增活动数据操作失败，人群规则为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "人群规则为空");
        }
        //基础执行信息验证
        List<EventActivityExecuteInfoBO> executeInfoBOList = eventActivityBO.getExecuteInfoBOList();
        AtomicInteger sumRatio = new AtomicInteger();
        executeInfoBOList.forEach(item -> sumRatio.addAndGet(item.getFlowRatio()));
        if (sumRatio.get() != 100) {
            log.error("EventActivityService#insertEventActivity 新增活动数据操作失败，执行信息数据异常 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "执行信息总比例不为100%");
        }
        eventActivityBO.setStatus(EventActivityStatusEnum.DRAFT);
        EventActivityPO eventActivityPO = EventActivityConvert.convertToEventActivityPO(eventActivityBO);
        boolean inserted = eventActivityRepository.insertEventActivity(eventActivityPO);
        if (inserted) {
            String decisionKey = EventKeyBuild.buildEventActivityInfoDecisionKey(eventActivityBO.getDecisionId());
            redisService.hSet(decisionKey, String.valueOf(eventActivityBO.getId()), JSONObject.toJSONString(eventActivityBO));
        }
        log.info("EventActivityService#insertEventActivity 新增活动数据操作成功 eventActivityBO：【{}】，结果：【{}】", JSONObject.toJSONString(eventActivityBO), inserted);
        return inserted;
    }

    @Override
    public Boolean updateEventActivity(EventActivityBO eventActivityBO) {
        if (eventActivityBO == null || eventActivityBO.getId() == null) {
            return false;
        }
        EventActivityBO alreadyData = queryEventActivityById(eventActivityBO.getId());
        if (alreadyData == null) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，活动数据不存在 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        //运行中或者已过期状态不允许操作
        if (alreadyData.getStatus().equals(EventActivityStatusEnum.RUNNING) || alreadyData.getStatus().equals(EventActivityStatusEnum.EXPIRED)) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，活动数据状态禁止操作 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.NOT_SUPPORT_OPERATE_STATUS);
        }
        //已经开始时间内容不允许操作
        if (alreadyData.getStartTime().after(new Date())) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，活动数据已经开始时间不允许操作 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.EVENT_ACTIVITY_RUNNING);
        }
        if (eventActivityBO.getStartTime() == null || eventActivityBO.getEndTime() == null || eventActivityBO.getStartTime().after(eventActivityBO.getEndTime())) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，活动时间数据为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "活动时间数据异常");
        }
        if (eventActivityBO.getDecisionId() == null || eventActivityBO.getExecuteRule() == null || CollectionUtils.isEmpty(eventActivityBO.getExecuteInfoBOList())) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，核心数据为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "核心为空");
        }
        //基础规则验证
        EventActivityRuleBO executeRule = eventActivityBO.getExecuteRule();
        if (executeRule.getHitBlackList() && executeRule.getBlackClassify() == null) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，黑名单规则为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "黑名单规则为空");
        }
        if (executeRule.getHitCrowd() && executeRule.getCrowdClassify() == null) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，人群规则为空 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "人群规则为空");
        }
        //基础执行信息验证
        List<EventActivityExecuteInfoBO> executeInfoBOList = eventActivityBO.getExecuteInfoBOList();
        AtomicInteger sumRatio = new AtomicInteger();
        executeInfoBOList.forEach(item -> sumRatio.addAndGet(item.getFlowRatio()));
        if (sumRatio.get() != 100) {
            log.error("EventActivityService#updateEventActivity 更新活动数据操作失败，执行信息数据异常 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR, "执行信息总比例不为100%");
        }
        eventActivityBO.setStatus(EventActivityStatusEnum.DRAFT);
        EventActivityPO eventActivityPO = EventActivityConvert.convertToEventActivityPO(eventActivityBO);
        boolean updated = eventActivityRepository.updateEventActivity(eventActivityPO);
        if (updated) {
            String decisionKey = EventKeyBuild.buildEventActivityInfoDecisionKey(eventActivityBO.getDecisionId());
            redisService.hSet(decisionKey, String.valueOf(eventActivityBO.getId()), JSONObject.toJSONString(eventActivityBO));
        }
        log.info("EventActivityService#updateEventActivity 更新活动数据操作成功 eventActivityBO：【{}】，结果：【{}】", JSONObject.toJSONString(eventActivityBO), updated);
        return updated;
    }

    @Override
    public Boolean removeEventActivity(Long id) {
        if (id == null || id <= 0) {
            return true;
        }
        EventActivityBO eventActivityBO = queryEventActivityById(id);
        if (eventActivityBO == null) {
            return true;
        }
        if (eventActivityBO.getStatus().equals(EventActivityStatusEnum.RUNNING)) {
            log.error("EventActivityService#removeEventActivity 删除活动数据操作失败，运行中的活动无法直接删除 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.NOT_SUPPORT_OPERATE_STATUS, "运行中的活动无法直接删除");
        }
        boolean removed = eventActivityRepository.removeEventActivityById(id);
        if (removed) {
            String decisionKey = EventKeyBuild.buildEventActivityInfoDecisionKey(eventActivityBO.getDecisionId());
            redisService.hDel(decisionKey, String.valueOf(eventActivityBO.getId()));
        }
        log.info("EventActivityService#removeEventActivity 删除活动数据操作成功 eventActivityBO：【{}】，结果：【{}】", JSONObject.toJSONString(eventActivityBO), removed);
        return removed;
    }

    @Override
    public EventActivityBO queryEventActivityById(Long id) {
        if (id == null || id <= 0) {
            return null;
        }
        EventActivityPO eventActivityPO = eventActivityRepository.queryEventActivityById(id);
        return EventActivityConvert.convertToEventActivityBO(eventActivityPO);
    }

    @Override
    public List<EventActivityBO> queryRunningEventActivityByDecision(Long decisionId) {
        if (decisionId == null || decisionId <= 0) {
            return Collections.emptyList();
        }
        String decisionKey = EventKeyBuild.buildEventActivityInfoDecisionKey(decisionId);
        Map<String, String> cachedValue = redisService.hGetAll(decisionKey);
        if (MapUtils.isNotEmpty(cachedValue)) {
            return cachedValue.values().stream()
                    .map(item -> JSONObject.parseObject(item, EventActivityBO.class))
                    .filter(item -> item.getEndTime().after(new Date()))
                    .collect(Collectors.toList());
        }
        List<EventActivityPO> eventActivityPOList = eventActivityRepository.queryEventActivityListByDecisionId(decisionId);
        if (CollectionUtils.isNotEmpty(eventActivityPOList)) {
            List<EventActivityBO> eventActivityBOList = eventActivityPOList.stream().map(EventActivityConvert::convertToEventActivityBO).collect(Collectors.toList());
            eventActivityBOList.forEach(item -> {
                String eventActivityKey = EventKeyBuild.buildEventActivityInfoDecisionKey(item.getDecisionId());
                redisService.hSet(eventActivityKey, String.valueOf(item.getId()), JSONObject.toJSONString(item));
                //避免组件的情况导致的缓存问题，次数获取运行中数据后将对应的关联数据也重新加载
                doHandleRunningReBuild(item);
            });
            return eventActivityBOList.stream()
                    .filter(item -> item.getEndTime().after(new Date()))
                    .collect(Collectors.toList());
        }
        log.warn("EventActivityService#queryRunningEventActivityByDecision 查询缓存和数据库都为空 decisionId:【{}】", decisionId);
        return Collections.emptyList();
    }

    @Override
    public Boolean updateEventActivityStatus(Long id, EventActivityStatusEnum oldStatus, EventActivityStatusEnum newStatus) {
        if (id == null || id < 0 || oldStatus == null || newStatus == null) {
            return false;
        }
        if (oldStatus.equals(newStatus)) {
            return true;
        }
        //TODO 关于状态流转的操作暂时不实现，后续可以加强次流程
        EventActivityBO eventActivityBO = queryEventActivityById(id);
        if (eventActivityBO == null) {
            log.error("EventActivityService#updateEventActivityStatus 更新活动数据操作失败，活动不存在 eventActivityBO：【{}】", JSONObject.toJSONString(eventActivityBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (eventActivityBO.getStatus().equals(newStatus)) {
            return true;
        }
        Boolean updated = eventActivityRepository.updateEventActivityStatus(id, oldStatus, newStatus);
        if (updated) {
            eventActivityBO.setStatus(newStatus);
            String key = EventKeyBuild.buildEventActivityInfoDecisionKey(eventActivityBO.getDecisionId());
            redisService.hSet(key, String.valueOf(eventActivityBO.getId()), JSONObject.toJSONString(eventActivityBO));
            if (newStatus.equals(EventActivityStatusEnum.RUNNING)) {
                doHandleRunningStatus(eventActivityBO);
            }
        }
        log.info("EventActivityService#updateEventActivityStatus 更新活动数据操作成功 eventActivityBO：【{}】，结果：【{}】", JSONObject.toJSONString(eventActivityBO), updated);
        return updated;
    }

    private void doHandleRunningStatus(EventActivityBO eventActivityBO) {
        //增加频次配置
        FrequencyConf frequencyConf = new FrequencyConf();
        frequencyConf.setActivityEndTime(eventActivityBO.getEndTime());
        frequencyConf.setDay(eventActivityBO.getExecuteRule().getFrequency().getDay());
        frequencyConf.setCount(eventActivityBO.getExecuteRule().getFrequency().getCount());
        frequencyHelper.saveFrequencyConf(eventActivityBO.getId(), frequencyConf);
        //增加AB分流配置
        List<SampleFlowConfig> sampleFlowConfigList = new ArrayList<>();
        for (EventActivityExecuteInfoBO executeInfoBO : eventActivityBO.getExecuteInfoBOList()) {
            SampleFlowConfig sampleFlowConfig = new SampleFlowConfig();
            sampleFlowConfig.setFlowName(executeInfoBO.getFlowName());
            sampleFlowConfig.setFlowRatio(executeInfoBO.getFlowRatio());
            sampleFlowConfig.setFlowStrategyCode(executeInfoBO.getFlowCode());
            sampleFlowConfigList.add(sampleFlowConfig);
        }
        abHelper.allocateBucket(String.valueOf(eventActivityBO.getId()), sampleFlowConfigList, (int) DateUtils.between(new Date(), eventActivityBO.getEndTime()).toMillis());
    }

    @Override
    public PageResult<EventActivityBO> queryEventActivityPageByCondition(EventActivityConditionBO eventActivityConditionBO) {
        if (eventActivityConditionBO == null) {
            return new PageResult<>();
        }
        EventActivityCondition eventActivityCondition = EventActivityConvert.convertToEventActivityCondition(eventActivityConditionBO);
        PageResult<EventActivityPO> pageResult = eventActivityRepository.queryEventActivityByCondition(eventActivityCondition);
        if (pageResult == null) {
            return PageResult.of(Lists.newArrayList(), eventActivityConditionBO.getPageIndex(), eventActivityConditionBO.getPageSize(), 0L);
        }
        PageResult<EventActivityBO> result = new PageResult<>();
        result.setResults(pageResult.getResults() == null ? null : pageResult.getResults().stream().map(EventActivityConvert::convertToEventActivityBO).collect(Collectors.toList()));
        result.setHasNext(pageResult.isHasNext());
        result.setTotal(pageResult.getTotal());
        result.setPageCount(pageResult.getPageCount());
        result.setPageNum(pageResult.getPageNum());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        result.setPageSize(pageResult.getPageSize());
        return result;
    }

    private void doHandleRunningReBuild(EventActivityBO eventActivityBO) {
        //增加频次配置
        FrequencyConf frequencyConf = new FrequencyConf();
        frequencyConf.setActivityEndTime(eventActivityBO.getEndTime());
        frequencyConf.setDay(eventActivityBO.getExecuteRule().getFrequency().getDay());
        frequencyConf.setCount(eventActivityBO.getExecuteRule().getFrequency().getCount());
        frequencyHelper.checkAndReBuildFrequencyConf(eventActivityBO.getId(), frequencyConf);
        //增加AB分流配置
        List<SampleFlowConfig> sampleFlowConfigList = new ArrayList<>();
        for (EventActivityExecuteInfoBO executeInfoBO : eventActivityBO.getExecuteInfoBOList()) {
            SampleFlowConfig sampleFlowConfig = new SampleFlowConfig();
            sampleFlowConfig.setFlowName(executeInfoBO.getFlowName());
            sampleFlowConfig.setFlowRatio(executeInfoBO.getFlowRatio());
            sampleFlowConfig.setFlowStrategyCode(executeInfoBO.getFlowCode());
            sampleFlowConfigList.add(sampleFlowConfig);
        }
        abHelper.reAllocateBucket(String.valueOf(eventActivityBO.getId()), sampleFlowConfigList, (int) DateUtils.between(new Date(), eventActivityBO.getEndTime()).toMillis());
    }
}
